#include "iap.h"
#include "userflash.h"

#define TIMEOUT             (0x100000)
#define PACK_SIZE            128

/*************xmodem 状态机*************/
#define X_STATE_START      0X00
#define X_STATE_RSEND      0X01  //请求主机发送数据
#define X_STATE_RDATA      0X02  //接收主机数据
#define X_STATE_DATAACK    0X03  //接收到数据后应答
#define X_STATE_DATANACK   0X04  //接收到数据非应答
#define X_STATE_EOTACK     0X05  //接收到结束信号应答
#define X_STATE_CAN        0X06
#define X_STATE_END        0XFF  


uint8_t xmodeSate;
uint8_t packNumber;

uint8_t rbuf[PACK_SIZE+10];    //实际上只需要128+2



//接收一个byte数据，0代表超时，1接收ok
uint8_t receiveOneByte(uint8_t *ch)
{
	uint32_t count=TIMEOUT;
	while(count-->0)
	{
		if(LL_USART_IsActiveFlag_RXNE(USART1))
		{
			*ch=LL_USART_ReceiveData8(USART1);
			return 1;
		}
	}
	return 0;
}

void sendOneByte(uint8_t ch)
{
	LL_USART_TransmitData8(USART1,ch);
	while(LL_USART_IsActiveFlag_TXE(USART1)){};
}

uint16_t CRC16_XMODEM(uint8_t *puchMsg, uint16_t usDataLen)
{
  uint16_t wCRCin = 0x0000;
  uint16_t wCPoly = 0x1021;
  uint8_t wChar = 0;
  
  while (usDataLen--) 	
  {
        wChar = *(puchMsg++);
        wCRCin ^= (wChar << 8);
        for(int i = 0;i < 8;i++)
        {
          if(wCRCin & 0x8000)
            wCRCin = (wCRCin << 1) ^ wCPoly;
          else
            wCRCin = wCRCin << 1;
        }
  }
  return (wCRCin) ;
}



//接收数据状态
//0-接收超时
//1-接收一包数据成功
//2-接收到EOT结束信号
//3-接收数据校验失败
uint8_t receiveData(uint8_t *rdata)
{
	uint8_t ch;
	uint8_t sta=0;
	uint16_t crc,rcrc;
	if(receiveOneByte(&ch)==0)sta=0;  //接收超时
	else 
	{
		switch (ch)
		{
			case SOH:
				for(uint8_t i=0;i<PACK_SIZE+4;i++)
				{
					if(receiveOneByte(rdata+i)==0) //中间出现接收超时
					{
						sta=0;
						break;
					}
				}
				crc=CRC16_XMODEM(rdata+2,PACK_SIZE);
				rcrc=(rdata[PACK_SIZE+2]<<8)+rdata[PACK_SIZE+3];
				if(crc==rcrc)   //如果接收到一包数据crc校验成功，证明接收成功
				{
						sta=1;
				}
				else sta=3;
				break;
			case EOT:
				sta=2;
				break;
		}
	}
	if(sta==1)
	{
			if(rdata[0]==packNumber)  //验证包号是否正确
			{
				flashAppWrite(APP_ADD+PACK_SIZE*(packNumber-1),(uint16_t *)(rdata+2),PACK_SIZE/2);  //把接收到的数据写入flash
				packNumber++;	
				xmodeSate=X_STATE_DATAACK;
				
			}
			else  //协议已经错乱，发送取消信号
			{
					xmodeSate=X_STATE_CAN;
			}
	}
	else if(sta==2)    
	{
		xmodeSate=X_STATE_EOTACK;
	}
	else if(sta==3)
	{
		xmodeSate=X_STATE_DATANACK;
	}
	else    //没有收到主机发送过来数据，重新开始发送'C'
	{
		xmodeSate=X_STATE_RSEND;
	}
	return sta;
}
//开始执行IAP
uint8_t startIap()
{
	xmodeSate=X_STATE_START;
	while(1)
	{
		switch (xmodeSate)
		{
			case X_STATE_START:
				packNumber=1;
				flashInit();
				xmodeSate=X_STATE_RSEND;
				break;
			case X_STATE_RSEND:
				sendOneByte('C');
				xmodeSate=X_STATE_RDATA;
				break;
			case X_STATE_RDATA:
				receiveData(rbuf);
				break;
			case X_STATE_DATAACK:
				sendOneByte(ACK);
				xmodeSate=X_STATE_RDATA;
				break;
			case X_STATE_DATANACK:
				sendOneByte(NAK);
				xmodeSate=X_STATE_RDATA;				
				break;
			case X_STATE_EOTACK:              //升级成功
				sendOneByte(ACK);
				xmodeSate=X_STATE_END;
				flashLock();
				return 1;			
				break;
			case X_STATE_CAN:
				sendOneByte(CAN);
				xmodeSate=X_STATE_END;
			  return 0;
				break;
			case X_STATE_END:
				break;		
		}			
	}
}






